package com.qf.service.impl;

import com.qf.pojo.Order;
import com.qf.service.OrderService;
import com.qf.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    /**
     *  ① 当dubbo扫描到这个注解时，向注册中心发起订阅OrderService这个接口对应的服务，会将这个提供者的信息拉取到本地并缓存
     *        同时会在本地基于提供者暴露的协议，ip，端口，以及接口信息，生成一个代理对象。代理带向内部实现的逻辑其实就是基于协议，ip，端口，以及接口信息
     *        向服务提供方启动的内置服务器发起网络请求（netty发起）
     *
     *  ② 会将第一步生成的代理对象注入到spring容器中。所以如果已经使用@Reference注入过对象后，后续如果还想继续使用这种类型的对象
     *      可以使用@Autowired注入。
     */
    //@Autowired

    /**
     * ① dubbo默认超时时间是1s
     *     可以在提供方或者消费方注解上配置timeout属性，配置超时时间。
     *     如果提供方或者消费方都有配置，那么以消费方配置为准
     *
     * ② 当发生超时时，提供方超时后，业务代码会继续向下执行，并不会中断。而且提供方业务默认是执行3次的（重试）。
     *      幂等性 - 多次操作结果一致，我们称之为幂等；多次操作结果不一致，称之为非幂等
     *          新增 - 非幂等操作
     *          查询 - 幂等操作
     *          删除 - 幂等操作
     *          更新 - 不一定
     *             update xx set name=yy where id = xx;  -- 幂等
     *             update xx set money=money-100 where id = xx; -- 非幂等
     *
     *
     *    注意：
     *      面对超时重试,我们业务是一个幂等操作，最终不会对数据造成影响，只是会额外消耗服务器资源.但是能够尽可能让业务执行成功
     *      面对超时重试,我们业务是一个非幂等操作，最终会对数据造成影响，这个是不允许的。所以此时我们要禁用重试
      */

    /**
     * random: 随机
     * ***roundrobin： 轮询 (会在admin控制端，将性能比较好的服务器的权重设置的更大，让他承载更多的请求)
     * leastactive： 最小活跃数,能者多劳（服务能力越强，更倾向于将请求发送给这台机器）
     * consistenthash: 一致性hash，当发送请求时，请求参数不变，就一致访问固定的那一台机器
     *      同步配置一个parameters属性  todo: consistenthash 单词所有字母小写
     *
     *
     * ***failover:  失败重试，重试的是其他集群中的服务器 （对于幂等性的操作选择这种方案）
     * ***failfast:  失败结束，一旦失败了，就结束访问（对于非幂等性的操作选择使用）
     * failsafe:  失败安全，失败了，对于用户来说不可见，不抛异常，直接将异常信息写入到日志文件中
     * failback:  失败重试，一值重试当前访问失败的机器，直到机器恢复访问能力
     * forking:   一次性给所有的集群机器都发送请求，只要有一个成功，就成功
     * broadcast: 一次性给所有机器发送请求，只要有一个失败，就失败
     */
    @Reference(timeout = 2000/*,retries = 0*/,
            version = "1.0",
            loadbalance = "roundrobin"/*,parameters = {"k1","v1"}*/,
            cluster = "failfast",
            stub = "com.qf.stub.OrderServiceStub",
            mock = "com.qf.mock.OrderServiceMock"
    ) //注入远程服务对象
    private OrderService orderService;

    @Override
    public List<Order> findById(Integer uid) throws InterruptedException {
        System.out.println("通过远程调用查询用户订单");
        return orderService.findByUid(uid);
    }
}
